function results = shape_read(filename)
% PURPOSE: reads an arcview shapfile and returns a structure 
%          that can be used by make_map() function
% -----------------------------------------------------
% USAGE: results = shape_read(filename)
% where: filename = an arcview file name without the extension
% ----------------------------------------------------------------------------------------
% Returns: a structure variable:
%  results.npoly = a scalar with # of polygon regions or data observations on the map
%  results.nvars = # of variables from the dbf file [should = the length(vnames)]
%  results.nobs  = # of observations from the dbf file [should = npoly]
%  results.xmin = an nobs-vector of minimum longitude for each region
%  results.xmax = an nobs-vector of maximum longitude for each region
%  results.ymin = an nobs-vector of minimum lattitude for each region
%  results.ymax = an nobs-vector of maximum lattitude for each region
%  results.nvertices = an nobs-vector of # of vertices for each region
%  results.nparts = an nobs-vector of # of parts for each region
%  results.xc = an nobs-vector with x-centroid for each polygon/ region
%  results.yc = an nobs-vector with y-centroid for each polygon/ region
%  results.data = (an nobs=npoly by nvars) matrix of sample data observations for each polygon/ region
%  results.vnames = variable names for data vectors from dbf file
% ---------------------------------------------------------------------------------------
%  results.x = an (n by nvertices) vector of polygon points, with NaN separators
%  results.y = an (n by nvertices) vector of polygon points, with NaN separators
%              (the same as poly(i).handles(i), but organized a one long vector
%               these can be used as carte argument to the geoxp functions carte = [results.x results.y])
% ----------------------------------------------------------------------------------------
% NOTES:
%
% 1) to load and plot a map involving npoly=nobs sample data observations
% results = shape_read('myarcfile');
% poly = make_map(results);
% to set the facecolor of the map polygons, using the handles in poly structure
% for i=1:results.npoly;
%  for k=1:results.nparts(i);
%  set(poly(i).handles(k),'FaceColor',[0 1 1]);
%  end;
% end;
%
% 2) to use the geoxp functions:
% % [results,poly] = shpfile_read('myarcfile');
% histomap(results.xc,results.yc,variable,nbcl,[results.x results.y], ...)
% ----------------------------------------------------------------------------------------
% see ALSO: arc_histmap(results, ...), arc_moranplot
% ----------------------------------------------------------------------------------------
% uses: a c-mex function shp_read.c, compile with mex shp_read.c shapelib.c
% ----------------------------------------------------------------------------------------

% written by: James P. LeSage 12/2003
% University of Toledo
% Department of Economics
% Toledo, OH 43606
% jlesage@spatial-econometrics.com

if nargin ~= 1
error('shpfile_read: Wrong # of input arguments');
end;

% call to mex file
[cartex,cartey,xmin,xmax,ymin,ymax,nvertices,nparts,xc,yc] = shp_read(filename);
% compile with:
% mex shp_read.c shapelib.c

ind = find(cartex ~= 0);
long = cartex(ind,1);
latt = cartey(ind,1);
npoly = length(xmin);
results.npoly = npoly;
results.xc = xc;
results.yc = yc;
clear xc;
clear yc;

results.x = long(1:end-1,1);
results.y = latt(1:end-1,1);
x = results.x;
y = results.y;

poly(1).fig_handle = figure('Visible','off');
handles = polyplot(long(1:end-1,1),latt(1:end-1,1),'fill',[0 0 0]);

clear long;
clear latt;

 % Process chunks separated by NaN .................
in = [0; find(isnan(x)); length(x)+1];
n = length(in)-1;
cnt = 1;
jj = 1;
while (jj <= n)
  ii = in(jj)+1:in(jj+1)-1;
  ii = [ii ii(1)];
  xx = x(ii); yy = y(ii);
if nparts(cnt,1) == 1
poly(cnt).handles(1,1) = handles(jj);
results.xmin(cnt) = xmin(cnt);
results.xmax(cnt) = xmax(cnt);
results.ymin(cnt) = ymin(cnt);
results.ymax(cnt) = ymax(cnt);
results.nvertices(cnt) = nvertices(cnt);
results.nparts(cnt) = nparts(cnt);
cnt = cnt+1;
jj = jj+1;
else
 for k=1:nparts(cnt,1);
  poly(cnt).handles(1,k) = handles(jj);
  jj = jj+1;
 end;
results.xmin(cnt) = xmin(cnt);
results.xmax(cnt) = xmax(cnt);
results.ymin(cnt) = ymin(cnt);
results.ymax(cnt) = ymax(cnt);
results.nvertices(cnt) = nvertices(cnt);
results.nparts(cnt) = nparts(cnt);
cnt = cnt+1;
end;
end;

clear xmin;
clear xmax;
clear ymin;
clear ymax;
clear nvertices;
clear nparts;


% clean up the invisible figure window stuff
hfig = gcf;
close(hfig);
clf reset;
close all;


% now read the dbf file and place the data into a structure
[datamatrix,vnames] = dbf_read(filename);

results.vnames = strvcat(vnames);
results.nvars = size(datamatrix,2);
results.nobs = size(datamatrix,1);
if results.nobs ~= results.npoly
warning('shpfile_read: # of shapefile polygons do not match # of data observations in dbf file');
end;
results.data = datamatrix;
clear datamatrix;

function [handles] = polyplot(x,y,a1,a2)
% POLYPLOT Plotting or filling polygons.
%	L = POLYPLOT(X,Y) plots polygon(s)
%	concatenated into coordinate vectors X, Y.
%	If X, Y consist of coordinates of several
%	polygons they must be separated by NaN:
%	X = [X1 NaN X2 NaN X3 ...]. In this case each
%	polygon is "closed" and plotted separately.
%	L is a vector of handles of lines defining
%	polygon boundaries, one handle per line.
%	L = POLYPLOT(X,Y,C) also specifies line color.
%	C can be a letter such as 'w', 'y', 'c', etc.,
%	a 1 by 3 vector in RGB format or a string of 
%	such letters, like 'rgby' or n by 3 matrix.
%	In the latter case this string or matrix plays the
%	role of color order for succession of polygons.
%	If the number of polygons is more than number of
%	colors, colors are cyclically repeated.
%
%	P = POLYPLOT(X,Y,'fill',C) fills polygons
%	creating a patch rather than a line and returns
%	patch handles P.
%
%	This program can also fill non-simply connected
%	polygons, such as ones with holes. It checks
%	the direction of each polygons separated by
%	NaN in coordinate vectors. If the contour is
%	clock-wise (signed area is negative) then it
%	interprets such a polygon as a "hole" and fills
%	it with the background color.

%  Copyright (c) 1995 by Kirill K. Pankratov,
%       kirill@plume.mit.edu.
%       06/25/95, 09/07/95  

%  May call AREA function.

 % Handle input ....................................
is_patch = 0;
clr = get(gca,'colororder');
if nargin>2
  lm = min(length(a1),4);
  names = ['fill '; 'patch'];
  is_patch = all(a1(1:lm)==names(1,1:lm));
  is_patch = is_patch | all(a1(1:lm)==names(2,1:lm));

  if is_patch
    if nargin>3, clr = a2; end
  else
    clr = a1;
  end
end
if isstr(clr), clr=clr(:); end
nclr = size(clr,1);
x = x(:); y = y(:);

 % Check hold state ............
if ~ishold, newplot, end

 % Setup a call ................
if is_patch
  call = 'patch';
  cpn = 'facecolor';
else
  call = 'line';
  cpn = 'color';
end
% call = ['p(jj)=' call '(''xdata'',xx,''ydata'',yy);'];
% call
 % Get color for "holes" polygons ..................
clrh = get(gca,'color');
if strcmp(clrh,'none'), clrh = get(gcf,'color'); end 

 % Process chunks separated by NaN .................
in = [0; find(isnan(x)); length(x)+1];
n = length(in)-1;
for jj=1:n
  ii = in(jj)+1:in(jj+1)-1;
  ii = [ii ii(1)];
  xx = x(ii); yy = y(ii);

  % Check area
  a(jj) = area(xx,yy);

  % Create the patch or line
  %eval(call)
  handles(jj) = patch(xx,yy,[1 0 0]);
  ic = rem(jj-1,nclr)+1;
  set(handles(jj),cpn,clr(ic,:))
end

 % If non-simply-connected patch, fill "holes" with 
 % background color ...............................
if is_patch & n>1
  % Find which polygons are inside which
  holes = find(a<0);
  % Set color
  set(handles(holes),'FaceColor',clrh)

end


function  a = area(x,y)
% AREA  Area of a planar polygon.
%	AREA(X,Y) Calculates the area of a 2-dimensional
%	polygon formed by vertices with coordinate vectors
%	X and Y. The result is direction-sensitive: the
%	area is positive if the bounding contour is counter-
%	clockwise and negative if it is clockwise.
%
%	See also TRAPZ.

%  Copyright (c) 1995 by Kirill K. Pankratov,
%	kirill@plume.mit.edu.
%	04/20/94, 05/20/95  

 % Make polygon closed .............
x = [x(:); x(1)];
y = [y(:); y(1)];

 % Calculate contour integral Int -y*dx  (same as Int x*dy).
lx = length(x);
a = -(x(2:lx)-x(1:lx-1))'*(y(1:lx-1)+y(2:lx))/2;


